package com.ruben.simpleboot.interceptor

import cn.hutool.core.util.ReflectUtil
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper
import com.baomidou.mybatisplus.core.toolkit.*
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor
import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper
import net.sf.jsqlparser.expression.*
import net.sf.jsqlparser.expression.Function
import net.sf.jsqlparser.expression.operators.conditional.AndExpression
import net.sf.jsqlparser.expression.operators.conditional.OrExpression
import net.sf.jsqlparser.expression.operators.relational.*
import net.sf.jsqlparser.schema.Column
import net.sf.jsqlparser.schema.Table
import net.sf.jsqlparser.statement.Statement
import net.sf.jsqlparser.statement.delete.Delete
import net.sf.jsqlparser.statement.insert.Insert
import net.sf.jsqlparser.statement.select.*
import net.sf.jsqlparser.statement.update.Update
import org.apache.ibatis.executor.Executor
import org.apache.ibatis.executor.statement.StatementHandler
import org.apache.ibatis.mapping.BoundSql
import org.apache.ibatis.mapping.MappedStatement
import org.apache.ibatis.mapping.SqlCommandType
import org.apache.ibatis.session.ResultHandler
import org.apache.ibatis.session.RowBounds
import java.sql.Connection
import java.sql.SQLException
import java.util.*
import java.util.function.Consumer
import java.util.function.Predicate
import java.util.stream.Collectors


/**
 * 回收站插件
 *
 * @author VampireAchao
 * @since 2022/9/30 16:20
 */
class RecycleBinInnerInterceptor(private var recycleBinLineHandler: RecycleBinLineHandler? = null) :
    JsqlParserSupport(),
    InnerInterceptor {

    @Throws(SQLException::class)
    override fun beforeQuery(
        executor: Executor?,
        ms: MappedStatement,
        parameter: Any?,
        rowBounds: RowBounds?,
        resultHandler: ResultHandler<*>?,
        boundSql: BoundSql?
    ) {
        if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.id, "recycleBin")) return
        val mpBs = PluginUtils.mpBoundSql(boundSql)
        mpBs.sql(parserSingle(mpBs.sql(), null))
    }

    /**
     * 执行 SQL 解析
     *
     * @param statement JsqlParser Statement
     * @return sql
     */
    override fun processParser(statement: Statement?, index: Int, sql: String?, obj: Any?): String {
        if (logger.isDebugEnabled) {
            logger.debug("SQL to parse, SQL: $sql")
        }
        var sql: String? = null
        if (statement is Insert) {
            processInsert((statement as Insert?)!!, index, sql, obj)
        } else if (statement is Select) {
            processSelect((statement as Select?)!!, index, sql, obj)
        } else if (statement is Update) {
            processUpdate((statement as Update?)!!, index, sql, obj)
        } else if (statement is Delete) {
            if (!RecycleThreadLocal.REAL_DELETE.get() && !recycleBinLineHandler!!.ignoreTable(statement.table.name)) {
                // 如果当前需要回收
                sql = Update().apply {
                    table = statement.table
                    where = statement.where
                    addRecycleUpdateCondition(this)
                }.toString()
            } else {
                processDelete((statement as Delete?)!!, index, sql, obj)
            }
        }
        sql = sql ?: statement.toString()
        if (logger.isDebugEnabled) {
            logger.debug("parse the finished SQL: $sql")
        }
        return sql
    }

    override fun beforePrepare(sh: StatementHandler?, connection: Connection?, transactionTimeout: Int?) {
        parseSql(sh)
    }

    private fun parseSql(sh: StatementHandler?) {
        val mpSh = PluginUtils.mpStatementHandler(sh)
        val ms = mpSh.mappedStatement()
        val sct = ms.sqlCommandType
        if (sct == SqlCommandType.INSERT ||
            sct == SqlCommandType.DELETE ||
            sct == SqlCommandType.UPDATE ||
            sct == SqlCommandType.SELECT
        ) {
            if (InterceptorIgnoreHelper.willIgnoreOthersByKey(ms.id, "recycleBin")) {
                return
            }
            val mpBs = mpSh.mPBoundSql()
            mpBs.sql(parserMulti(mpBs.sql(), null))
        }
    }

    /**
     * [StatementHandler.getBoundSql] 操作前置处理
     *
     *
     * 只有 [BatchExecutor] 和 [ReuseExecutor] 才会调用到这个方法
     *
     * @param sh StatementHandler(可能是代理对象)
     */
    override fun beforeGetBoundSql(sh: StatementHandler?) {
        parseSql(sh)
    }

    override fun processSelect(select: Select, index: Int, sql: String?, obj: Any?) {
        processSelectBody(select.selectBody)
        val withItemsList = select.withItemsList
        if (!CollectionUtils.isEmpty(withItemsList)) {
            withItemsList.forEach(Consumer { selectBody: WithItem? ->
                processSelectBody(
                    selectBody
                )
            })
        }
    }

    protected fun processSelectBody(selectBody: SelectBody?) {
        if (selectBody == null) {
            return
        }
        if (selectBody is PlainSelect) {
            processPlainSelect(selectBody)
        } else if (selectBody is WithItem) {
            processSelectBody(selectBody.subSelect.selectBody)
        } else {
            val operationList = selectBody as SetOperationList
            val selectBodyList = operationList.selects
            if (CollectionUtils.isNotEmpty(selectBodyList)) {
                selectBodyList.forEach(Consumer { body: SelectBody? -> processSelectBody(body) })
            }
        }
    }

    override fun processInsert(insert: Insert, index: Int, sql: String?, obj: Any?) {
        if (recycleBinLineHandler!!.ignoreTable(insert.table.name)) {
            // 过滤退出执行
            return
        }
        val columns = insert.columns
        if (CollectionUtils.isEmpty(columns)) {
            // 针对不给列名的insert 不处理
            return
        }
        val recycleBinColumn = recycleBinLineHandler!!.getRecycleBinColumn()
        if (recycleBinLineHandler!!.ignoreInsert(columns, recycleBinColumn)) {
            // 针对已给出回收列的insert 不处理
            return
        }
        columns.add(Column(recycleBinColumn))

        // fixed gitee pulls/141 duplicate update
        val duplicateUpdateColumns = insert.duplicateUpdateExpressionList
        if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
            val equalsTo = if (RecycleThreadLocal.ONLY_SHOW_RECYCLE.get()) NotEqualsTo() else EqualsTo()
            equalsTo.leftExpression = StringValue(recycleBinColumn)
            equalsTo.rightExpression = recycleBinLineHandler!!.getRecycleBin()
            duplicateUpdateColumns.add(equalsTo)
        }
        val select = insert.select
        if (select != null) {
            processInsertSelect(select.selectBody)
        } else if (insert.itemsList != null) {
            // fixed github pull/295
            val itemsList = insert.itemsList
            if (itemsList is MultiExpressionList) {
                itemsList.expressionLists.forEach(Consumer { el: ExpressionList ->
                    el.expressions.add(
                        recycleBinLineHandler!!.getRecycleBin()
                    )
                })
            } else {
                (itemsList as ExpressionList).expressions.add(
                    recycleBinLineHandler!!.getRecycleBin()
                )
            }
        } else {
            throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId")
        }
    }

    /**
     * update 语句处理
     */
    override fun processUpdate(update: Update, index: Int, sql: String?, obj: Any?) {
        val table = update.table
        if (recycleBinLineHandler!!.ignoreTable(table.name)) {
            // 过滤退出执行
            return
        }
        update.where = andExpression(table, update.where)
        val tableInfo = TableInfoHelper.getTableInfo(update.table.name)
        if (update.updateSets.any { it.columns.any { it.columnName == tableInfo.logicDeleteFieldInfo.column } } &&
            !RecycleThreadLocal.REAL_DELETE.get()
        ) {
            // 如果当前需要回收
            if (obj is PluginUtils.MPBoundSql) {
                val boundSql = ReflectUtil.getFieldValue(obj, "delegate") as BoundSql
                update.updateSets.mapNotNull { u -> u.expressions.find { e -> e is JdbcParameter } }
                    .sortedByDescending { (it as JdbcParameter).index }
                    .forEach { boundSql.parameterMappings.removeAt((it as JdbcParameter).index - 1) }
                update.updateSets.clear()
            }
            addRecycleUpdateCondition(update)
        }
    }

    /**
     * delete 语句处理
     */
    override fun processDelete(delete: Delete, index: Int, sql: String?, obj: Any?) {
        if (recycleBinLineHandler!!.ignoreTable(delete.table.name)) {
            // 过滤退出执行
            return
        }
        delete.where = andExpression(delete.table, delete.where)
    }

    /**
     * delete update 语句 where 处理
     */
    protected fun andExpression(table: Table?, where: Expression?): BinaryExpression {
        //获得where条件表达式
        val equalsTo = if (RecycleThreadLocal.ONLY_SHOW_RECYCLE.get()) NotEqualsTo() else EqualsTo()
        equalsTo.leftExpression = getAliasColumn(table)
        equalsTo.rightExpression = recycleBinLineHandler!!.getRecycleBin()
        return if (null != where) {
            if (where is OrExpression) {
                AndExpression(equalsTo, Parenthesis(where))
            } else {
                AndExpression(equalsTo, where)
            }
        } else equalsTo
    }

    /**
     * 处理 insert into select
     *
     *
     * 进入这里表示需要 insert 的表启用了回收,则 select 的表都启动了
     *
     * @param selectBody SelectBody
     */
    protected fun processInsertSelect(selectBody: SelectBody) {
        val plainSelect = selectBody as PlainSelect
        val fromItem = plainSelect.fromItem
        if (fromItem is Table) {
            // fixed gitee pulls/141 duplicate update
            processPlainSelect(plainSelect)
            appendSelectItem(plainSelect.selectItems)
        } else if (fromItem is SubSelect) {
            appendSelectItem(plainSelect.selectItems)
            processInsertSelect(fromItem.selectBody)
        }
    }


    /**
     * 追加 SelectItem
     *
     * @param selectItems SelectItem
     */
    protected fun appendSelectItem(selectItems: MutableList<SelectItem?>) {
        if (CollectionUtils.isEmpty(selectItems)) {
            return
        }
        if (selectItems.size == 1) {
            val item = selectItems[0]
            if (item is AllColumns || item is AllTableColumns) {
                return
            }
        }
        selectItems.add(SelectExpressionItem(Column(recycleBinLineHandler!!.getRecycleBinColumn())))
    }

    /**
     * 处理 PlainSelect
     */
    protected fun processPlainSelect(plainSelect: PlainSelect) {
        //#3087 github
        val selectItems = plainSelect.selectItems
        if (CollectionUtils.isNotEmpty(selectItems)) {
            selectItems.forEach(Consumer { selectItem: SelectItem? ->
                processSelectItem(
                    selectItem
                )
            })
        }

        // 处理 where 中的子查询
        val where = plainSelect.where
        processWhereSubSelect(where)

        // 处理 fromItem
        val fromItem = plainSelect.fromItem
        val list = processFromItem(fromItem)
        var mainTables: MutableList<Table?>? = ArrayList(list)

        // 处理 join
        val joins = plainSelect.joins
        if (CollectionUtils.isNotEmpty(joins)) {
            mainTables = processJoins(mainTables, joins)
        }

        // 当有 mainTable 时，进行 where 条件追加
        if (CollectionUtils.isNotEmpty(mainTables)) {
            plainSelect.where = builderExpression(where, mainTables)
        }
    }

    private fun processFromItem(fromItem: FromItem): List<Table?> {
        // 处理括号括起来的表达式
        var fromItem: FromItem? = fromItem
        while (fromItem is ParenthesisFromItem) {
            fromItem = fromItem.fromItem
        }
        val mainTables: MutableList<Table?> = ArrayList()
        // 无 join 时的处理逻辑
        if (fromItem is Table) {
            mainTables.add(fromItem)
        } else if (fromItem is SubJoin) {
            // SubJoin 类型则还需要添加上 where 条件
            val tables: List<Table?>? = processSubJoin(fromItem)
            mainTables.addAll(tables!!)
        } else {
            // 处理下 fromItem
            processOtherFromItem(fromItem)
        }
        return mainTables
    }

    /**
     * 处理where条件内的子查询
     *
     *
     * 支持如下:
     * 1. in
     * 2. =
     * 3. >
     * 4. <
     * 5. >=
     * 6. <=
     * 7. <>
     * 8. EXISTS
     * 9. NOT EXISTS
     *
     *
     * 前提条件:
     * 1. 子查询必须放在小括号中
     * 2. 子查询一般放在比较操作符的右边
     *
     * @param where where 条件
     */
    protected fun processWhereSubSelect(where: Expression?) {
        if (where == null) {
            return
        }
        if (where is FromItem) {
            processOtherFromItem(where as FromItem?)
            return
        }
        if (where.toString().indexOf("SELECT") > 0) {
            // 有子查询
            if (where is BinaryExpression) {
                // 比较符号 , and , or , 等等
                val expression = where
                processWhereSubSelect(expression.leftExpression)
                processWhereSubSelect(expression.rightExpression)
            } else if (where is InExpression) {
                // in
                val inExpression = where.rightExpression
                if (inExpression is SubSelect) {
                    processSelectBody(inExpression.selectBody)
                }
            } else if (where is ExistsExpression) {
                // exists
                processWhereSubSelect(where.rightExpression)
            } else if (where is NotExpression) {
                // not exists
                processWhereSubSelect(where.expression)
            } else if (where is Parenthesis) {
                processWhereSubSelect(where.expression)
            }
        }
    }

    protected fun processSelectItem(selectItem: SelectItem?) {
        if (selectItem is SelectExpressionItem) {
            val selectExpressionItem = selectItem
            if (selectExpressionItem.expression is SubSelect) {
                processSelectBody((selectExpressionItem.expression as SubSelect).selectBody)
            } else if (selectExpressionItem.expression is Function) {
                processFunction(selectExpressionItem.expression as Function)
            }
        }
    }

    /**
     * 处理函数
     *
     * 支持: 1. select fun(args..) 2. select fun1(fun2(args..),args..)
     *
     *
     *
     *  fixed gitee pulls/141
     *
     * @param function
     */
    protected fun processFunction(function: Function) {
        val parameters = function.parameters
        parameters?.expressions?.forEach(Consumer { expression: Expression? ->
            if (expression is SubSelect) {
                processSelectBody(expression.selectBody)
            } else if (expression is Function) {
                processFunction(expression)
            }
        })
    }

    /**
     * 处理子查询等
     */
    protected fun processOtherFromItem(fromItem: FromItem?) {
        // 去除括号
        var fromItem = fromItem
        while (fromItem is ParenthesisFromItem) {
            fromItem = fromItem.fromItem
        }
        if (fromItem is SubSelect) {
            val subSelect = fromItem
            if (subSelect.selectBody != null) {
                processSelectBody(subSelect.selectBody)
            }
        } else if (fromItem is ValuesList) {
            logger.debug("Perform a subQuery, if you do not give us feedback")
        } else if (fromItem is LateralSubSelect) {
            val lateralSubSelect = fromItem
            if (lateralSubSelect.subSelect != null) {
                val subSelect = lateralSubSelect.subSelect
                if (subSelect.selectBody != null) {
                    processSelectBody(subSelect.selectBody)
                }
            }
        }
    }

    /**
     * 处理 sub join
     *
     * @param subJoin subJoin
     * @return Table subJoin 中的主表
     */
    private fun processSubJoin(subJoin: SubJoin): MutableList<Table?>? {
        var mainTables: MutableList<Table?>? = ArrayList()
        if (subJoin.joinList != null) {
            val list = processFromItem(subJoin.left)
            mainTables!!.addAll(list)
            mainTables = processJoins(mainTables, subJoin.joinList)
        }
        return mainTables
    }

    /**
     * 处理 joins
     *
     * @param mainTables 可以为 null
     * @param joins      join 集合
     * @return List<Table> 右连接查询的 Table 列表
    </Table> */
    private fun processJoins(mainTables: MutableList<Table?>?, joins: List<Join?>): MutableList<Table?>? {
        // join 表达式中最终的主表
        var mainTables = mainTables
        var mainTable: Table? = null
        // 当前 join 的左表
        var leftTable: Table? = null
        if (mainTables == null) {
            mainTables = ArrayList()
        } else if (mainTables.size == 1) {
            mainTable = mainTables[0]
            leftTable = mainTable
        }

        //对于 on 表达式写在最后的 join，需要记录下前面多个 on 的表名
        val onTableDeque: Deque<List<Table?>?> = LinkedList()
        for (join in joins) {
            // 处理 on 表达式
            val joinItem = join!!.rightItem

            // 获取当前 join 的表，subJoint 可以看作是一张表
            var joinTables: MutableList<Table?>? = null
            if (joinItem is Table) {
                joinTables = ArrayList()
                joinTables.add(joinItem)
            } else if (joinItem is SubJoin) {
                joinTables = processSubJoin(joinItem)
            }
            if (joinTables != null) {

                // 如果是隐式内连接
                if (join.isSimple) {
                    mainTables!!.addAll(joinTables)
                    continue
                }

                // 当前表是否忽略
                val joinTable = joinTables[0]
                var onTables: List<Table?>? = null
                // 如果不要忽略，且是右连接，则记录下当前表
                if (join.isRight) {
                    mainTable = joinTable
                    if (leftTable != null) {
                        onTables = listOf(leftTable)
                    }
                } else if (join.isLeft) {
                    onTables = listOf(joinTable)
                } else if (join.isInner) {
                    onTables = if (mainTable == null) {
                        listOf(joinTable)
                    } else {
                        Arrays.asList(mainTable, joinTable)
                    }
                    mainTable = null
                }
                mainTables = ArrayList()
                if (mainTable != null) {
                    mainTables.add(mainTable)
                }

                // 获取 join 尾缀的 on 表达式列表
                val originOnExpressions = join.onExpressions
                // 正常 join on 表达式只有一个，立刻处理
                if (originOnExpressions.size == 1 && onTables != null) {
                    val onExpressions: MutableList<Expression?> = LinkedList()
                    onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables))
                    join.onExpressions = onExpressions
                    leftTable = joinTable
                    continue
                }
                // 表名压栈，忽略的表压入 null，以便后续不处理
                onTableDeque.push(onTables)
                // 尾缀多个 on 表达式的时候统一处理
                if (originOnExpressions.size > 1) {
                    val onExpressions: MutableCollection<Expression?> = LinkedList()
                    for (originOnExpression in originOnExpressions) {
                        val currentTableList = onTableDeque.poll()
                        if (CollectionUtils.isEmpty(currentTableList)) {
                            onExpressions.add(originOnExpression)
                        } else {
                            onExpressions.add(builderExpression(originOnExpression, currentTableList))
                        }
                    }
                    join.onExpressions = onExpressions
                }
                leftTable = joinTable
            } else {
                processOtherFromItem(joinItem)
                leftTable = null
            }
        }
        return mainTables
    }

    /**
     * 处理条件
     */
    protected fun builderExpression(currentExpression: Expression?, tables: List<Table?>?): Expression? {
        // 没有表需要处理直接返回
        if (CollectionUtils.isEmpty(tables)) {
            return currentExpression
        }
        // 构造每张表的条件
        val tempTables = tables!!.stream()
            .filter { x: Table? ->
                !recycleBinLineHandler!!.ignoreTable(
                    x!!.name
                )
            }
            .collect(Collectors.toList())

        // 没有表需要处理直接返回
        if (CollectionUtils.isEmpty(tempTables)) {
            return currentExpression
        }
        val recycleBin = recycleBinLineHandler!!.getRecycleBin()
        val equalsTos = tempTables.stream()
            .map { item: Table? ->
                if (RecycleThreadLocal.ONLY_SHOW_RECYCLE.get()) NotEqualsTo(
                    getAliasColumn(item),
                    recycleBin
                ) else EqualsTo(
                    getAliasColumn(item),
                    recycleBin
                )
            }
            .collect(Collectors.toList())

        // 注入的表达式
        var injectExpression: Expression = equalsTos[0]
        // 如果有多表，则用 and 连接
        if (equalsTos.size > 1) {
            for (i in 1 until equalsTos.size) {
                injectExpression = AndExpression(injectExpression, equalsTos[i])
            }
        }
        if (currentExpression == null) {
            return injectExpression
        }
        return if (currentExpression is OrExpression) {
            AndExpression(Parenthesis(currentExpression), injectExpression)
        } else {
            AndExpression(currentExpression, injectExpression)
        }
    }

    /**
     * 回收字段别名设置
     *
     * recycleBin 或 tableAlias.recycleBin
     *
     * @param table 表对象
     * @return 字段
     */
    protected fun getAliasColumn(table: Table?): Column {
        val column = StringBuilder()
        // 为了兼容隐式内连接，没有别名时条件就需要加上表名
        if (table!!.alias != null) {
            column.append(table.alias.name)
        } else {
            column.append(table.name)
        }
        column.append(StringPool.DOT).append(recycleBinLineHandler!!.getRecycleBinColumn())
        return Column(column.toString())
    }

    override fun setProperties(properties: Properties?) {
        PropertyMapper.newInstance(properties).whenNotBlank("recycleBinLineHandler",
            { clazzName: String? ->
                ClassUtils.newInstance(
                    clazzName
                )
            }
        ) { recycleBinLineHandler: RecycleBinLineHandler? ->
            this.recycleBinLineHandler = recycleBinLineHandler
        }
    }

    private fun addRecycleUpdateCondition(update: Update) {
        // 回收时更新回收字段
        update.addUpdateSet(
            Column(recycleBinLineHandler!!.getRecycleBinColumn()),
            Column("NOW()")
        )
        update.addUpdateSet(
            Column(recycleBinLineHandler!!.getRecyclerIdColumn()),
            recycleBinLineHandler!!.getRecyclerId()
        )
    }

}


class RecycleBinLineHandler {
    companion object {
        const val NOT_RECYCLE_VALUE = "2001-01-01 00:00:00"
    }

    /**
     * 获取回收 ID 值表达式，只支持单个 ID 值
     *
     *
     *
     * @return 回收 ID 值表达式
     */
    fun getRecycleBin(): Expression {
        return StringValue(NOT_RECYCLE_VALUE)
    }

    /**
     * 获取回收字段名
     *
     *
     * 默认字段名叫: gmt_recycled
     *
     * @return 回收字段名
     */
    fun getRecycleBinColumn(): String {
        return "gmt_recycled"
    }

    /**
     * 获取将数据移入回收站的用户id字段
     *
     *
     * 默认字段名叫: recycler_id
     *
     * @return 将数据移入回收站的用户id字段
     */
    fun getRecyclerIdColumn(): String {
        return "recycler_id"
    }

    /**
     * 获取将数据移入回收站的用户id
     *
     *
     * 默认值为: -1
     *
     * @return 将数据移入回收站的用户id
     */
    fun getRecyclerId(): Expression {
        return LongValue(-1L)
    }

    /**
     * 根据表名判断是否忽略拼接回收条件
     *
     *
     * 默认都要进行解析并拼接回收条件
     *
     * @param tableName 表名
     * @return 是否忽略, true:表示忽略，false:需要解析并拼接回收条件
     */
    fun ignoreTable(tableName: String?): Boolean {
        // 只有包含了回收时间字段的，才需要拼接回收条件
        val tableInfo = TableInfoHelper.getTableInfo(tableName)
        val notHasRecycleBinColumn =
            Predicate<List<String>> { columns -> columns.contains(getRecycleBinColumn()) }.negate()
        val notHasRecyclerIdColumn =
            Predicate<List<String>> { columns -> columns.contains(getRecyclerIdColumn()) }.negate()
        return notHasRecycleBinColumn.and(notHasRecyclerIdColumn)
            .test(tableInfo?.fieldList?.map { it.column } ?: emptyList())
    }

    /**
     * 忽略插入回收字段逻辑
     *
     * @param columns        插入字段
     * @param recycleBinColumn 回收 ID 字段
     * @return
     */
    fun ignoreInsert(columns: List<Column>, recycleBinColumn: String?): Boolean {
        return columns.stream().map { obj: Column -> obj.columnName }.anyMatch { i: String ->
            i.equals(recycleBinColumn, ignoreCase = true)
        }
    }

}

class RecycleThreadLocal {

    companion object {
        val ONLY_SHOW_RECYCLE: ThreadLocal<Boolean> = InheritableThreadLocal.withInitial { false }
        val REAL_DELETE: ThreadLocal<Boolean> = InheritableThreadLocal.withInitial { false }
    }
}